﻿using System.Collections.Generic;

namespace seqdiag
{
    public class CallTree
    {
        public CallTree Parent;
        public CallTree Next;
        public CallTree Previous;
        public List<CallTree> Children = new List<CallTree>();
        public string ClassName;
        public string MethodName;
        public string ReturnValue;
        public int Depth;

        public CallTree Root
        {
            get
            {
                return Parent != null ? Parent.Root : this;
            }
        }

        public bool IsRoot
        {
            get
            {
                return this == Root;
            }
        }

        private static int GetLineDepth(string line)
        {
            int position = 0;
            while (line[position] == '\t')
            {
                position++;
            }
            return position;
        }

        public CallTree(string line)
        {
            string noIndentLine = line.Replace("\t", "");
            string[] splittedLine = noIndentLine.Split(':');
            ClassName = splittedLine[0];
            MethodName = splittedLine.Length > 1 ? splittedLine[1] : string.Empty;
            ReturnValue = splittedLine.Length > 2 ? splittedLine[2] : string.Empty;
            Depth = GetLineDepth(line);
        }

        public void AppendChild(CallTree child)
        {
            child.Parent = this;
            child.Depth = Depth + 1;
            if (Children.Count > 0)
            {
                (child.Previous = Children[Children.Count - 1]).Next = child;
            }
            Children.Add(child);
        }

        public void AppendSibling(CallTree sibling)
        {
            Parent.AppendChild(sibling);
        }

        public static CallTree FromLines(string[] lines)
        {
            CallTree currentTree = null;
            foreach (string line in lines)
            {
                currentTree = CallTree.CreateRelativeTree(currentTree, line);
            }
            return currentTree.Root;
        }
        
        private static CallTree CreateRelativeTree(CallTree currentTree, string line)
        {
            CallTree call = new CallTree(line);

            if (currentTree != null)
            {
                if (call.Depth == currentTree.Depth)
                {
                    currentTree.AppendSibling(call);
                    return call;
                }
                else if (call.Depth > currentTree.Depth)
                {
                    currentTree.AppendChild(call);
                    return call;
                }
                else
                {
                    while (currentTree.Depth > call.Depth)
                    {
                        currentTree = currentTree.Parent;
                    }
                    currentTree.AppendSibling(call);
                    return call;
                }
            }
            else
            {
                return new CallTree(line);
            }
        }

    }

}
